/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package porownywanieofertapp;
import java.util.*;

/**
 *
 * @author Wlodek
 */

class CompOfCenowo implements Comparator<Oferta> {
    public int compare(Oferta arg0, Oferta arg1) {
        return arg0.getCena()-arg1.getCena();
    }
}

class CompOfMetrazowo implements Comparator<Oferta> {
    public int compare(Oferta arg0, Oferta arg1) {
        return arg0.getCena()-arg1.getCena();
    }
}
class OfertaRadixSort {
    public static void OfertaRadixSort(ArrayList<Oferta> l){
        List[] kolejkaZliczanych ;
        int ilosc_kubkow=0;

        //po rozkladowe
        ilosc_kubkow=2;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for(int i=0;i<ilosc_kubkow;i++)
            kolejkaZliczanych[i] = new LinkedList();

        for(int i=0;i<l.size();i++){
            if(l.get(i).getRozkladowe()==true){
                kolejkaZliczanych[0].add(l.get(i));
            }
            else{
                kolejkaZliczanych[1].add(l.get(i));
            }
        }
        l.clear();
        l.addAll(kolejkaZliczanych[0]);
        l.addAll(kolejkaZliczanych[1]);
        
        
        //sortowanie po pietrze
        ilosc_kubkow=200;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for(int i=0;i<ilosc_kubkow;i++)
            kolejkaZliczanych[i] = new LinkedList();

        for(int i=0;i<l.size();i++){
            if(l.get(i).getPietro()>=0 && l.get(i).getPietro()<200)
                kolejkaZliczanych[l.get(i).getPietro()%ilosc_kubkow].add(l.get(i));
            else if(l.get(i).getPietro()>=200)kolejkaZliczanych[ilosc_kubkow-1].add(l.get(i));
            else kolejkaZliczanych[0].add(l.get(i)); //dla uproszczenia przyjmujemy, ze mieszkanie na -1 pietrze jest tyle samo warte co mieszkanie ma parterze
        }
        l.clear();
        for(int i=0;i<ilosc_kubkow;i++){
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po roku budowy
        ilosc_kubkow=400;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for(int i=0;i<ilosc_kubkow;i++)
            kolejkaZliczanych[i] = new LinkedList();

        for(int i=0;i<l.size();i++){
            if(l.get(i).getRokBudowy()-1900>=0)
                kolejkaZliczanych[ilosc_kubkow-1-(l.get(i).getRokBudowy()-1900)%ilosc_kubkow].add(l.get(i)); //algorytm dziala poprawnie do roku 2300
            else kolejkaZliczanych[0].add(l.get(i)); //przyjmujemy, ze budynki zbudowane przed 1900 rokiem to zabytki
        }
        l.clear();
        for(int i=0;i<ilosc_kubkow;i++){
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po liczbie pokoi
        ilosc_kubkow=60;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for(int i=0;i<ilosc_kubkow;i++)
            kolejkaZliczanych[i] = new LinkedList();

        for(int i=0;i<l.size();i++){
            if(l.get(i).getLiczbePokoi()>=0 && l.get(i).getLiczbePokoi()<60)
                kolejkaZliczanych[ilosc_kubkow-1-l.get(i).getLiczbePokoi()%ilosc_kubkow].add(l.get(i));
            else if( l.get(i).getLiczbePokoi()>=60)kolejkaZliczanych[0].add(l.get(i));
            else kolejkaZliczanych[ilosc_kubkow-1].add(l.get(i));// nie zwracamy wyjatku w razie bledu, poniewaz komplikowaloby to w znaczny sposob nasza aplikacje
        }
        l.clear();
        for(int i=0;i<ilosc_kubkow;i++){
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po metrazu
        ilosc_kubkow=50;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for(int i=0;i<ilosc_kubkow;i++)
            kolejkaZliczanych[i] = new LinkedList();

        for(int i=0;i<l.size();i++){
            if(l.get(i).getMetraz()>=0 && l.get(i).getMetraz()<1000)
                kolejkaZliczanych[ilosc_kubkow-((l.get(i).getMetraz()/20)%ilosc_kubkow)-1].add(l.get(i));
            else if(l.get(i).getMetraz()>=1000)kolejkaZliczanych[0].add(l.get(i));
            else kolejkaZliczanych[ilosc_kubkow-1].add(l.get(i));// ujemny metraz moglby byc nadużywany w pozycjonowaniu ofert, dlatego wpisujemy go na koniec
        }
        l.clear();
        for(int i=0;i<ilosc_kubkow;i++){
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po cenie
        ilosc_kubkow=500;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for(int i=0;i<ilosc_kubkow;i++)
            kolejkaZliczanych[i] = new LinkedList();

        for(int i=0;i<l.size();i++){
            if(l.get(i).getCena()>=0 && l.get(i).getCena()<500000)
                kolejkaZliczanych[(l.get(i).getCena()/1000)%ilosc_kubkow].add(l.get(i));// algorytm zaklada ze statystycznie bardzo rzadko ceny miekszan sa wieksze niz 500 tys, wtedy bowiem dziala niepoprawnie dla cen
            else kolejkaZliczanych[ilosc_kubkow-1].add(l.get(i));// za wysoka lub ujemna cena moglaby byc nadużywana w pozycjonowaniu ofert, dlatego wpisujemy ja na koniec
        }
        l.clear();
        for(int i=0;i<ilosc_kubkow;i++){
            l.addAll(kolejkaZliczanych[i]);
        }

    }
}

class PorownanieKaskadoweOfert implements Comparator<Oferta> {
 
    public int compare(Oferta arg0, Oferta arg1) {

        //kolejne sortowanie
        if(arg0.getCena()!=arg1.getCena()){ //sortowanie po większej cenie
            return arg0.getCena()-arg1.getCena();
        }
        else if (arg0.getMetraz()!=arg1.getMetraz()){ //sortowanie po większym metrażu
                return arg1.getMetraz()-arg0.getMetraz();
        }
        else if (arg0.getLiczbePokoi()!=arg1.getLiczbePokoi()){ //sortowanie po liczbie pokoi
                return arg1.getLiczbePokoi()-arg0.getLiczbePokoi();
        }
        else if (arg0.getRokBudowy()!=arg1.getRokBudowy()){ //po roku budowy
                return arg1.getRokBudowy()-arg0.getRokBudowy();
        }
        else if (arg0.getPietro()!=arg1.getPietro()){ //im mniejsze piętro, tym lepsza oferta
                return arg0.getPietro()-arg1.getPietro();
        }
        else if (arg0.getRozkladowe()!=arg1.getRozkladowe()){ //jeżeli pierwsze mieszkanie jest rozkładowe, to znaczy że jest lepsze
            if(arg0.getRozkladowe() == true)
                return 1;
            else return 0;
        }
        else return 0;
    }
}

public class Fasada {

    private ArrayList<Oferta> wyszukaneOferty;
    /**
     * Metoda stworzona przez grupe odpowiedzialna za PU Wyszukaj Oferty
     * @param wzorzec
     * @return
     */
    public ArrayList<Oferta> wyszukaj(Oferta wzorzec)
    {
        ArrayList<Oferta> al = new ArrayList<Oferta>();
        al.add(wzorzec);
        for(int j=0;j<10;j++){
             Object[] arg = new Object[15];
            arg[0]=(int)(130000+j*1000);
            arg[1]=(double)1;
            arg[2]=(double)2;
            arg[3]=3;
            arg[4]=(boolean)false;
            arg[5]=new int[4];
            for(int i=0;i<4;i++)((int[])arg[5])[0]=i;
            arg[6]=6;
            for(int i=7;i<11;i++)arg[i]=String.valueOf(i)+"ToString";
            arg[11]=11;
            arg[12]=12;
            arg[13]=new int[4];
            for(int i=0;i<4;i++)((int[])arg[13])[0]=i;
            arg[14]="TEST";
        FabrykaAbstrakcyjna f = new FabrykaStandard();
        Oferta a = f.stworzWzorzec(arg);
        al.add(a);
        }
        Object[] arg = new Object[15];
            arg[0]=130000;
            arg[1]=(double)1;
            arg[2]=(double)2;
            arg[3]=3;
            arg[4]=(boolean)true;
            arg[5]=new int[4];
            for(int i=0;i<4;i++)((int[])arg[5])[0]=i;
            arg[6]=6;
            for(int i=7;i<11;i++)arg[i]=String.valueOf(i)+"ToString";
            arg[11]=12;
            arg[12]=12;
            arg[13]=new int[4];
            for(int i=0;i<4;i++)((int[])arg[13])[0]=i;
            arg[14]="TEST";
        FabrykaAbstrakcyjna f = new FabrykaStandard();
        Oferta a = f.stworzWzorzec(arg);
        al.add(a);

        return al;
    }

    private ArrayList<Oferta> wyszukaj_m_z_n(int m)
    {
        ArrayList<Oferta> al = new ArrayList<Oferta>();
        al.addAll(this.wyszukaneOferty);

        //nasza metoda inteligentnie rozstrzyga czy warto uzywac sortowania pozycyjnego, czy korzystniej uzyc sortowania szybkiego
        /*
         * zlozonosc sortowania pozycyjnego (+zliczanie): 6*(n+1212)
         * zlozonosc sortowania szybkiego: 6*n*log_2(n)
         * dla n>185 lepszy jest algorytm sortowania pozycyjnego
         * */
        if(al.size()>185)
            OfertaRadixSort.OfertaRadixSort(al);
        else Collections.sort((List)al);

        int rozmiar=al.size();
        if(rozmiar>3){
            for(int i=3;i<rozmiar;i++){
                al.remove(al.get(3));
            }
        }
        return al;
    }

    public String zestawOferty(Object[] obj)
    {
        FabrykaAbstrakcyjna f = new FabrykaStandard();
        Oferta wzorzec = f.stworzWzorzec(obj);

        if(wyszukaneOferty == null)wyszukaneOferty = wyszukaj(wzorzec);
        String s = wyszukaj_m_z_n(obj.length/15).toString();
        
        return s;
        
    }
}
